-
Couldn't load subscription status.
- Fork 20
Update to use the microgrid API v0.18 #1283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v1.x.x
Are you sure you want to change the base?
Conversation
This introduces the new microgrid API v0.18. Signed-off-by: Leandro Lucarella <[email protected]>
Signed-off-by: Leandro Lucarella <[email protected]>
The microgrid API now doesn't support not reporting a rated fuse for a grid connection, so we don't need to test for that case anymore. Signed-off-by: Leandro Lucarella <[email protected]>
This introduces the new microgrid API v0.17. Signed-off-by: Leandro Lucarella <[email protected]>
The battery pool bounds calculation is buggy and these tests are wrong (see frequenz-floss#1180). By switching to using ranges of bounds, the buggy behaviour changes and make these tests fail. Fixing them is difficult without switching to using ranges natively first, so we just skip these tests for now. Signed-off-by: Leandro Lucarella <[email protected]>
60cf5b2 to
a996c07
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these are all the TODOs/FIXMEs I wrote when doing the update. It would be good to get some feedback.
| # FIXME: This might not be true forever, but the service for now seems to send | ||
| # all metrics with the same timestamp for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this one can be removed, at least IIRC @tiyash-basu-frequenz confirmed this was going to be like this for the time being. In any case, this is a temporary transitional module, at some point we should start using the telemetry messages as they come from the API.
| if not samples.states: | ||
| return class_(component_id=samples.component_id, timestamp=timestamp) | ||
|
|
||
| # FIXME: Maybe we can have more than one, in which case we need to merge them? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @tiyash-basu-frequenz also confirmed this was fine for now, but I don't remember if the idea is that more than one could come in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for EV chargers, we will have component state and cable state, both of which are necessary for its operation. But I guess @tiyash-basu-frequenz means that they will both be inside states[0].states, which is also a list. We will only not have multiple sets of states.
In that case, we just need to update the warning message below.
| # FIXME: All of this have now a default of 0.0 because this is what it was done when | ||
| # we used the API v0.15, as we accessed the fields without checking if the fields | ||
| # really existed, so the defaul protobuf value of 0.0 for floats was used. | ||
| # We might beed to review this and if they are not present interpret them as None | ||
| # instea. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is tricky, I guess we can leave it as it is now and will have to come back to it forcibly when removing this temporary adaption layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # FIXME: All of this have now a default of 0.0 because this is what it was done when | |
| # we used the API v0.15, as we accessed the fields without checking if the fields | |
| # really existed, so the defaul protobuf value of 0.0 for floats was used. | |
| # We might beed to review this and if they are not present interpret them as None | |
| # instea. | |
| # FIXME: All of this have now a default of 0.0 because this is what it was doing when | |
| # we used the API v0.15, as we accessed the fields without checking if the fields | |
| # really existed, so the default protobuf value of 0.0 for floats was used. | |
| # We might need to review this and if they are not present interpret them as None | |
| # instead. |
Also, it is the "adaptation" layer.
| # FIXME: We assume only one range is present | ||
| # If one bound is None, we assume 0 to match the previous | ||
| # behavior of v0.15, but this should eventually be fixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we'll also fix this when removing this adaption layer, not sure if it is worth adding a separate issue for this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can disable pylint fixme check for this entire module and keep the FIXMEs as they are now to remember to address these issues when removing this adaption layer.
| # Old code: | ||
| # return self.component_state not in ( | ||
| # EVChargerComponentState.AUTHORIZATION_REJECTED, | ||
| # EVChargerComponentState.ERROR, | ||
| # ) and self.cable_state in ( | ||
| # EVChargerCableState.EV_LOCKED, | ||
| # EVChargerCableState.EV_PLUGGED, | ||
| # ) | ||
| # TODO: Verify this logic is correct |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you can check this @shsms ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a comment about the cable states, written below.
| component.id | ||
| for component in component_graph.predecessors(battery_id) | ||
| if component.category == ComponentCategory.INVERTER | ||
| # TODO: Shouldn't this be (SolarInverter, HybridInverter)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shsms ? Maybe it is better to create a separate issue anyways as this was a pre-existing issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were not doing that because there were still a lot of edge configs from the early days that didn't specify the type of the inverter. Maybe things have changed now and we can start with a log message if the inverter type is not set.
| # TODO: This was using ErrorLevel.CRITICAL to see if an error was critical or | ||
| # warning. I guess now we use the separate errors and warnings fields. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you have a look at this one too @shsms ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense I think.
| # TODO: This is old validation logic, which should probably be removed | ||
| if component.id == ComponentId(0) and not isinstance( | ||
| component, GridConnectionPoint | ||
| ): | ||
| issues.append( | ||
| "Component with ID 0 should be a GridConnectionPoint, " | ||
| f"but it is a {component!r} instead." | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this check is safe to remove. I only found a previous check in an unused method _correct_graph_errors, removed in 635914c. I think I wrote this code before committing that removal.
FYI @tiyash-basu-frequenz @shsms @ela-kotulska-frequenz, I will remove this check unless someone complains.
| # TODO: This code is unreacheable, as T can't be None. We need to | ||
| # figure out which case this was supposed to handle. Maybe we need | ||
| # some sentinel value or to allow None in T. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shsms maybe you can check this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like it stopped being T | None here: bf22d6d
The handling for this case can go away as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only read a little bit of the big commit
| if not samples.states: | ||
| return class_(component_id=samples.component_id, timestamp=timestamp) | ||
|
|
||
| # FIXME: Maybe we can have more than one, in which case we need to merge them? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for EV chargers, we will have component state and cable state, both of which are necessary for its operation. But I guess @tiyash-basu-frequenz means that they will both be inside states[0].states, which is also a list. We will only not have multiple sets of states.
In that case, we just need to update the warning message below.
| ValueError: if the given id is unknown or has a different type. | ||
| """ | ||
| # pylint: disable-next=import-outside-toplevel,cyclic-import | ||
| from frequenz.sdk import microgrid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not relative path instead: from .. import microgrid
| # FIXME: All of this have now a default of 0.0 because this is what it was done when | ||
| # we used the API v0.15, as we accessed the fields without checking if the fields | ||
| # really existed, so the defaul protobuf value of 0.0 for floats was used. | ||
| # We might beed to review this and if they are not present interpret them as None | ||
| # instea. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # FIXME: All of this have now a default of 0.0 because this is what it was done when | |
| # we used the API v0.15, as we accessed the fields without checking if the fields | |
| # really existed, so the defaul protobuf value of 0.0 for floats was used. | |
| # We might beed to review this and if they are not present interpret them as None | |
| # instea. | |
| # FIXME: All of this have now a default of 0.0 because this is what it was doing when | |
| # we used the API v0.15, as we accessed the fields without checking if the fields | |
| # really existed, so the default protobuf value of 0.0 for floats was used. | |
| # We might need to review this and if they are not present interpret them as None | |
| # instead. |
Also, it is the "adaptation" layer.
| sample, | ||
| ) | ||
|
|
||
| self.active_power_per_phase = cast(PhaseTuple, tuple(active_power_per_phase)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow, amazing this doesn't happen automatically, given that it is just an alias.
| and bool( | ||
| { | ||
| ComponentStateCode.EV_CHARGING_CABLE_LOCKED_AT_EV, | ||
| ComponentStateCode.EV_CHARGING_CABLE_LOCKED_AT_STATION, | ||
| } | ||
| & self.states | ||
| or { | ||
| ComponentStateCode.EV_CHARGING_CABLE_PLUGGED_AT_EV, | ||
| ComponentStateCode.EV_CHARGING_CABLE_PLUGGED_AT_STATION, | ||
| } | ||
| & self.states |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we probably need to drop the *_AT_STATION codes. Cable connected to the station doesn't mean the other end of the cable has a car attached.
| # TODO: This was using ErrorLevel.CRITICAL to see if an error was critical or | ||
| # warning. I guess now we use the separate errors and warnings fields. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense I think.
| # FIXME: There was a semantic change here, before the component data had only | ||
| # one state, and now it has a set of states, for now we are considering the | ||
| # component to be working if any of its states is valid. Maybe we need to switch | ||
| # to the negative and consider a component not working if is in any known | ||
| # invalid state instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds unlikely, unless there's a bug, buf if there are multiple contradictory states for a component for the same timestamp, then we'll have to assume the component is broken.
| # FIXME: There was a semantic change here, before the component data had only | ||
| # one state, and now it has a set of states, for now we are considering the | ||
| # component to be working if any of its states is valid. Maybe we need to switch | ||
| # to the negative and consider a component not working if is in any known | ||
| # invalid state instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll have to assume the component is broken.
| { | ||
| ComponentStateCode.EV_CHARGING_CABLE_LOCKED_AT_EV, | ||
| ComponentStateCode.EV_CHARGING_CABLE_LOCKED_AT_STATION, | ||
| } | ||
| & ev_data.states | ||
| or { | ||
| ComponentStateCode.EV_CHARGING_CABLE_PLUGGED_AT_EV, | ||
| ComponentStateCode.EV_CHARGING_CABLE_PLUGGED_AT_STATION, | ||
| } | ||
| & ev_data.states |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too, we have to drop the AT_STATION states. An ev charger can't be assigned power if it doesn't have an EV attached, and that's what the is_working method is really about.
| # TODO: This code is unreacheable, as T can't be None. We need to | ||
| # figure out which case this was supposed to handle. Maybe we need | ||
| # some sentinel value or to allow None in T. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like it stopped being T | None here: bf22d6d
The handling for this case can go away as well.
This is a WIP PR, it still needs a lot of cleaning up, but all tests should be passing (minus
pylintbecause I added a few FIXME/TODOs.This PR is mostly created for having early feedback, and to allow doing some experiments to see how this works in the real world before start cleaning it up. It probably makes more sense to look at the resulting File Changes than going commit by commit at this stage.
@shsms FYI.